#pragma once

#include <memory>
#include <string>


#include "OrderedMessage.h"
#include "SequenceStream.h"
#include "NamedSubject.h"

namespace streamdb {


class MemoryObserver : public NamedObserver<OrderedMessage> {
public:
    typedef NamedSubject<OrderedMessage> StreamProducer;

    class StreamConsumer : public NamedObserver<OrderedMessage> {
    public:
        explicit StreamConsumer(const std::string & name) : NamedObserver(name), received(0) {}
        ~StreamConsumer()override {}

        void setStream(const std::shared_ptr<SequenceStream<OrderedMessage>> & stream) {
            this->stream = stream;
        }
        std::shared_ptr<SequenceStream<OrderedMessage>> getStream() const {
            return stream;
        }
        int64_t getRecieved() const{
            return received;
        }
        void setRecieved(int64_t value){
            received = value;
        }
    private:
        std::shared_ptr<SequenceStream<OrderedMessage>> stream;        
        int64_t received;
    };


    MemoryObserver() ;
    ~MemoryObserver() override {}

    void update(const OrderedMessage & object) override ;
    
    void attach(std::shared_ptr<StreamConsumer> & sc );
    void detach(std::shared_ptr<StreamConsumer> & sc);

private:
    std::shared_ptr<SequenceStream<OrderedMessage>> stream;
    std::unique_ptr<StreamProducer> subject;
};


class UserLogin : public MemoryObserver::StreamConsumer {
public:
    UserLogin():MemoryObserver::StreamConsumer("user") {}
    ~UserLogin()override {}

    UserLogin(const UserLogin &) = delete;
    UserLogin & operator=(const UserLogin &) = delete;

    void update(const OrderedMessage & object) override ;
};

class NetSubject : public NamedSubject<OrderedMessage> {
public:
    NetSubject(const std::string & name): NamedSubject(name){}
    ~NetSubject() override{
    }

    NetSubject(const NetSubject &) = delete;
    NetSubject & operator=(const NetSubject &) = delete;

    void notify(const OrderedMessage & msg) const override;
};

}//namespace streamdb

